package cn.edu.gznu.wecampus.core.common.api;

import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.edu.gznu.wecampus.core.common.entity.jpa.Role;
import cn.edu.gznu.wecampus.core.common.entity.jpa.RolePermission;
import cn.edu.gznu.wecampus.core.common.entity.jpa.RoleApiPermission;
import cn.edu.gznu.wecampus.core.common.repository.jpa.ApiPermissionRepository;
import cn.edu.gznu.wecampus.core.common.repository.jpa.RoleApiPermissionRepository;
import cn.edu.gznu.wecampus.core.common.repository.jpa.RolePermissionRepository;
import cn.edu.gznu.wecampus.core.web.FormVo;
import cn.edu.gznu.wecampus.core.web.IAddRest;
import cn.edu.gznu.wecampus.core.web.IEditRest;
import cn.edu.gznu.wecampus.core.web.IRemoveRest;
import cn.edu.gznu.wecampus.core.web.ISearch;
import cn.edu.gznu.wecampus.core.web.RestResponseElement;
import cn.edu.gznu.wecampus.core.web.SearchVo;
import cn.edu.gznu.wecampus.core.web.annotation.SearchParam;

import lombok.Getter;
import lombok.Setter;

@RestController
@RequestMapping("/api/common/role")
public class RoleApi implements
	ISearch<Role, String, RoleApi.RoleSearchVo>,
	IAddRest<Role, String, RoleApi.RoleFormVo>,
	IEditRest<Role, String, RoleApi.RoleFormVo>,
	IRemoveRest<Role, String> {
	
	@Autowired
	private RolePermissionRepository rolePermissionRepository;
	
	@Autowired
	private ApiPermissionRepository apiPermissionRepository;
	
	@Autowired
	private RoleApiPermissionRepository roleApiPermissionRepository;

	@Getter
	@Setter
	public static class RoleSearchVo extends SearchVo<Role, String> {
		@SearchParam(fields = {"roleName"}, operator = "like")
		private String roleName;
	}

	@Getter
	@Setter
	public static class RoleFormVo extends FormVo<String> {
		@NotEmpty(message = "角色名称不能为空")
		private String roleName;
	}

	@Override
	public void processAddEntity(@Valid RoleFormVo form, Role entity) throws Exception {
		entity.setRoleName(form.getRoleName());
		this.getRepository().saveAndFlush(entity);
	}

	@Override
	public void processEditEntity(@Valid RoleFormVo form, Role entity) throws Exception {
		entity.setRoleName(form.getRoleName());
		this.getRepository().saveAndFlush(entity);
	}

	@Override
	public void processRemoveEntity(Role entity) {
		this.getRepository().delete(entity);
	}
	
	@Getter
	@Setter
	public static class AssignPermissionsFormVo extends FormVo<String> {
		private List<PermissionFormVo> permissions = new LinkedList<PermissionFormVo>();
	}

	@Getter
	@Setter
	public static class PermissionFormVo extends FormVo<String> {
		private String method;
		private String url;
	}
	
	@PostMapping("assignPermissions")
	@Transactional
	public RestResponseElement assignPermissions(@Valid @RequestBody AssignPermissionsFormVo form) {
		Role role = getRepository().findOne(form.getId());
		rolePermissionRepository.deleteAll(rolePermissionRepository.findByRole(role));
		rolePermissionRepository.saveAll(
			form.getPermissions().stream().map(permission -> {
				RolePermission rolePermission = new RolePermission();
				rolePermission.setRole(role);
				rolePermission.setPermission(permission.getId());
				return rolePermission;
			}).collect(Collectors.toList())
		);
		
		roleApiPermissionRepository.deleteAll(roleApiPermissionRepository.findByRole(role));
		form.getPermissions().forEach(permission -> {
			String api = permission.getMethod() + " " + permission.getUrl();
			roleApiPermissionRepository.saveAll(
				apiPermissionRepository.findByApi(api).stream().map(apiPermission -> {
					RoleApiPermission roleApiPermission = new RoleApiPermission();
					roleApiPermission.setRole(role);
					roleApiPermission.setApiPermission(apiPermission);
					return roleApiPermission;
				}).collect(Collectors.toList())
			);
		});
		return this.createRestResponseElement(role);
	}
}
